package com.itHsuSE.experiment;

/**
 * @author Hsu琛君珩
 * @version 1.0
 */
public class Experiment6_3 {
    public static void main(String[] args) {
        // 创建售票员对象，初始有2张5元和0张20元
        Seller seller = new Seller(2, 0);
        System.out.println("售票员初始资金情况：");
        System.out.println("  20元纸币数量：" + seller.getTwenty() + " 张");
        System.out.println("  5元纸币数量：" + seller.getFive() + " 张");

        // 创建两名顾客的线程，李平支付20元，张红支付5元
        Runnable runnable1 = new Customer(seller, "李平", 20);
        Runnable runnable2 = new Customer(seller, "张红", 5);

        // 启动顾客线程
        new Thread(runnable1).start();
        new Thread(runnable2).start();
    }
}

// 售票员类
class Seller {
    public static final int PRICE = 5; // 电影票价格
    private int five; // 5元纸币数量
    private int twenty; // 20元纸币数量

    // 构造函数，初始化售票员的钱
    public Seller(int five, int twenty) {
        this.five = five;
        this.twenty = twenty;
    }

    // 获取5元纸币数量
    public int getFive() {
        return five;
    }

    // 获取20元纸币数量
    public int getTwenty() {
        return twenty;
    }

    // 顾客购票，传入顾客姓名和支付的总金额
    public synchronized boolean change(String customer, int payment) {
        // 计算找零金额
        int moneyChange = payment - PRICE;

        // 如果顾客支付刚好票价
        if (payment == PRICE) {
            System.out.println("售票员收到 " + payment + " 元钱，递给 " + customer + " 1 张入场券");
            this.five += 1; // 5元纸币数量+1
            return true;
        }

        // 计算需要的20元纸币数量和5元纸币数量
        int twentyChange = moneyChange / 20;
        int fiveChange = moneyChange % 20 / 5;

        // 判断售票员是否有足够的纸币找零
        if (this.twenty >= twentyChange && this.five >= fiveChange) {
            moneyChange = 20 * twentyChange + 5 * fiveChange;
            System.out.println("售票员收到 " + payment + " 元钱，递给 " + customer + " 1 张电影票，并找零 " + moneyChange + " 元");
            this.twenty -= twentyChange;
            this.five -= fiveChange;
            return true;
        }

        // 购票失败，没有足够的找零钱
        return false;
    }
}

// 顾客类，实现了Runnable接口，表示可以作为线程运行
class Customer implements Runnable {
    private final Seller seller; // 顾客要购票的售票员
    private final String name; // 顾客姓名
    private final int payment; // 顾客支付的总金额

    // 构造函数，初始化顾客信息
    public Customer(Seller seller, String name, int payment) {
        this.seller = seller;
        this.name = name;
        this.payment = payment;
    }

    @Override
    public void run() {
        System.out.println(name + "支付 " + payment + " 元购票。");
        boolean flag = seller.change(name, payment);

        while (!flag) {
            System.out.println("售票员没有找零，" + name + " 等待中");
            synchronized (seller) {
                try {
                    seller.wait(); // 顾客等待售票员找零
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(name + "重新支付 " + payment + " 元购票。");
            flag = seller.change(name, payment);
        }
        synchronized (seller) {
            seller.notifyAll(); // 通知其他等待的顾客
        }
    }
}
